<?php
/**
 * 物流工具类
 *
 * 物流模块工具类注意及说明
 * 以下use模块请不要互相伤害
 *
 * @author    xiecz <xiecz@yunys.com.cn>
 * @copyright 2016 QuanZhouYunYiShang Inc.
 */
namespace App\Services\Tool;
use Log;
use Illuminate\Support\Facades\DB;
use App\Services\Tool\DataBase\SQL;
use App\Services\Tool\GeneralTool;

class ExpressTool{
    protected $DBTABLE = 'debuglee_express';
    /**
        物流全
     */
    public static function get_express_list(){
        $lists = SQL::get(['table' => 'express',
                           'where' => []]);
        return $lists;
    }

    /**
        物流公司代码获取物流公司名称
     */
    public static function get_express_name_by_express_id($input){
        $express_name = SQL::pluck(['table' => 'express',
                                    'where' => ['express_id' => $input],
                                    'pluck' => 'express_name']);
        return isset($express_name) ? $express_name : '';
    }

    public static function sayHolle()
    {
         return env('message');
    }


    /**
     * 获取快递信息
     * @param  string $expressNumber  快递单号
     * @param  string $expressCompany 快递公司编码 例如:yuantong
     * @param  string $expressForm    出发地城市，省-市-区，非必填，填了有助于提升签收状态的判断的准确率，请尽量提供
     * @param  string $expressTo      目的地城市，省-市-区，非必填，填了有助于提升签收状态的判断的准确率，且到达目的地后会加大监控频率，请尽量提供
     * @param  string $userMobile     收件人的手机号，提供后快递100会向该手机号对应的QQ号推送【发货】、【同城派件】、【签收】三种信息，非必填，只能填写一个
     * @param  string $seller         寄件商家的名称，如果是平台方，则直接提供平台方名称，如果是平台上的商家，则提供商家名称。
     * @param  string $commodity      寄给收件人的商品名
     * @param  string $isCheckCompany 是否检查快递公司编码
     * @return bool                   成功返回true  失败false
     * @return mixed                  成功返回快递信息，失败返回false
     */
    public function getExpress($expressNumber, $expressCompany='', $expressForm='', $expressTo='', $userMobile='', $seller='', $commodity='', $isCheckCompany=false){

        if (empty($expressNumber)) {
            return false;
        }

        //查询数据库中是是否拥有快递信息
        $results = self::getExpressInfoByExpressNumber($expressNumber);

        if (!empty($results)) {
            // 数据库中发现物流数据 直接返回数据。

            // 判断数据库中的数据是否已经超过24小时未更新,若订单处在未签收状态,实时查询一次数据

            $updateTime = strtotime($results[0]->updated_at);
            $limitTime  = time() - $updateTime;

            if ($results[0]->api_status != 'shutdown' && $limitTime > 60*60*24) {

                $expressResult = self::realTimeGetExpressData($expressNumber, $expressCompany);

                if (empty($expressResult) || $expressResult == false) {
                    return false;
                }

                self::updateExpressByResult($expressResult);
            }


            $results = self::getExpressInfoByExpressNumber($expressNumber);
            // 格式化数据后返回
            $results[0]->express_data = unserialize($results[0]->express_data);
            return $results[0];
        } else {
            // 数据库中找不到任何资料,发起订阅
            // 如果无快递公司编码,发起快递单号所属公司猜想
            if (empty($expressCompany)) {
                $guessExpressCompanyCode = self::guessExpressCodeForExpressNumber($expressNumber);
                // 如果快递公司公司编码联想失败 终止订阅
                return false;
            }

            $subscribeExpress = self::subscribeExpressInfo($expressNumber, $expressCompany, $expressForm, $expressTo, $userMobile, $seller, $commodity, $isCheckCompany);

            // if ($subscribeExpress == false) {
            //  return false;
            // }

            // // 完成订阅,返回初次订阅数据;
            // return array();

            // 无法回调查询, 开启实时查询
            $expressResult = self::realTimeGetExpressData($expressNumber, $expressCompany);

            if (empty($expressResult) || $expressResult == false) {
                return false;
            }

            $responseData = array();
            // 将数据存入数据库中
            $expressInfo = array();
            $expressInfo['order_id']        = '';
            $expressInfo['api_status']      = $expressResult['status'];
            $expressInfo['express_company'] = $expressResult['com'];
            $expressInfo['express_number']  = $expressResult['nu'];
            $expressInfo['ischeck_packer']  = $expressResult['ischeck'];
            $expressInfo['express_state']   = $expressResult['state'];
            // // 转码数据
            $exp_arr = array();
            $i=0;
            foreach ($expressResult['data'] as $k => $v) {
                $exp_arr[$i]['time']    = $v['time'];
                $exp_arr[$i]['ftime']   = $v['ftime'];
                $exp_arr[$i]['context'] = $v['context'];
                $i++;
            }
            $expressInfo['express_data'] = serialize($exp_arr);
            $expressInfo['created_at'] = date('Y-m-d H:i:s', time());
            $expressInfo['updated_at'] = date('Y-m-d H:i:s', time());

            $insert = DB::table($this->DBTABLE)->insert($expressInfo);

            // 取出数据
            $results = self::getExpressInfoByExpressNumber($expressNumber);
            $results[0]->express_data = unserialize($results[0]->express_data);
            return $results[0];
        }
    }


    /**
     * 通过快递单号联想快递公司编码
     */
    public function guessExpressCodeForExpressNumber($expressNumber){
        if (empty($expressNumber)) {
            return false;
        }

        try {

            $url  = env('GUESS_EXPRESS_COMPANY_URL');
            $url .= '?num=' . $expressNumber . '&key=' . env("AUTH_KEY");

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL,$url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_TIMEOUT,10);

            // curl_setopt($ch, CURLOPT_POSTFIELDS, );
            $output = curl_exec($ch);
            //返回提交结果，格式与指定的格式一致（result=true代表成功）
            curl_close($ch);
        } catch (Exception $e) {
            return false;
        }

        $expressCompanyResult = json_decode($output);

        // 匹配数据可能会返回多个,因此只取其中一条数据作为返回值

        if (empty($expressCompanyResult)) {
            // TODO 通知快递公司名字联想失败
            return false;
        }

        $guessExpressCompany = $expressCompanyResult['0']->comCode;

        return $guessExpressCompany;
    }

    /**
     * 订阅请求
     * 订阅请求是指由贵公司发起的web请求，用于声明贵公司需要我方帮忙跟踪某个快递公司的某个运单号，一个单号订阅成功一次即可，快递100收到订阅后会对该单号进行监控与推送。
     *
     * @param  string $expressCompany 快递公司编码 例如:yuantong
     * @param  string $expressNumber  快递单号
     * @param  string $expressForm    出发地城市，省-市-区，非必填，填了有助于提升签收状态的判断的准确率，请尽量提供
     * @param  string $expressTo      目的地城市，省-市-区，非必填，填了有助于提升签收状态的判断的准确率，且到达目的地后会加大监控频率，请尽量提供
     * @param  string $userMobile     收件人的手机号，提供后快递100会向该手机号对应的QQ号推送【发货】、【同城派件】、【签收】三种信息，非必填，只能填写一个
     * @param  string $seller         寄件商家的名称，如果是平台方，则直接提供平台方名称，如果是平台上的商家，则提供商家名称。
     * @param  string $commodity      寄给收件人的商品名
     * @param  string $isCheckCompany 是否检查快递公司编码
     * @return bool                   成功返回true  失败false
     */
    public function subscribeExpressInfo($expressCompany, $expressNumber, $expressForm='', $expressTo='', $userMobile='', $seller='', $commodity='', $isCheckCompany=false)
    {
        if (empty($expressCompany) || empty($expressNumber)) {
            return false;
        }

        $paramArray = array();
        $paramArray['company'] = $expressCompany;
        $paramArray['number']  = $expressNumber;
        $paramArray['from']    = $expressForm;
        $paramArray['to']      = $expressTo;
        $paramArray['key']     = env('AUTH_KEY');
        $paramArray['parameters']['callbackurl'] = asset(env('CALL_BACK_URL'));
        $paramArray['parameters']['salt'] = self::hashSalt($expressNumber);
        $paramArray['parameters']['resultv2'] = '0';
        $paramArray['parameters']['mobiletelephone'] = $userMobile;
        $paramArray['parameters']['seller'] = $seller;
        $paramArray['parameters']['commodity'] = $commodity;

        // 发起订阅请求
        $getExpressData = $this->getExpressData($paramArray);

        return $getExpressData;
    }

    /**
     * 发送订阅请求
     * @param  array $params 订阅参数
     * @return mix 成功返回数据，失败返回false
     */
    public function getExpressData($params){

        if (empty($params)) {
            return false;
        }

        $url = env('REQUEST_RUL');

        $postData = array();
        $postData['schema'] = 'json';
        $postData['param'] = '{"company":"'.$params['company'].'","number":"'.$params['number'].'","from":"'.$params['from'].'","to":"'.$params['to'].'","key":"'.$params['key'].'","parameters":{"callbackurl":"'.asset(env('CALL_BACK_URL')).'","salt":"'.$params['parameters']['salt'].'"}}';

        try{
            Log::info("-------------订阅信息-------------");
            Log::info($postData);
        }catch(\Exception $e){
            SQL::insert(array('table'=>'active_logs',
                              'insert'=>array('message'=>json_encode($postData),'created_at'=>time())));
        }

        $o="";
        foreach ($postData as $k=>$v)
        {
            $o.= "$k=".urlencode($v)."&";       //默认UTF-8编码格式
        }

        $postData=substr($o,0,-1);

        try {

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_URL,$url);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
            curl_setopt($ch, CURLOPT_TIMEOUT,10);
            $output = curl_exec($ch);
            //返回提交结果，格式与指定的格式一致（result=true代表成功）

            try{
                Log::info('********* 快递订阅 ********');
                Log::info($output);
            }catch(\Exception $e){
                SQL::insert(array('table'=>'active_logs',
                                  'insert'=>array('message'=>$output,'created_at'=>time())));
            }

            curl_close($ch);
        } catch (Exception $e) {
            return false;
        }

        $result = json_decode($output);


        if (empty($result) || !isset($result->returnCode)) {
            return false;
        }


        if ($result->returnCode != '200') {
            return false;
        }

        return $result;
    }



    public function calllBack($param, $sign = ''){
        if (empty($param) || empty($sign)) {
            return false;
        }


        try{
            $expressData = json_decode($param);

            if (empty($expressData) || !isset($expressData)) {
                $response = '{"result":"false", "returnCode":"500","message":"json解析失败"}';
                return $response;
            }

            //取得快递单号
            if (!isset($expressData->lastResult->nu) && empty($expressData->lastResult->nu)) {
                $response = '{"result":"false", "returnCode":"500","message":"无快递单号"}';
                return $response;
            } else {
                $expressNumber = $expressData->lastResult->nu;
            }


            // 校验快递数据
            $salt = self::hashSalt($expressNumber);
            $checkSign = strtoupper(md5($param . $salt));
            if ($sign != $checkSign) {
                $response = '{"result":"false", "returnCode":"500","message":"数据校验失败"}';
                return $response;
            }

            $results = array();
            // 校验成功,储存相关数据
            $results = self::getExpressInfoByExpressNumber($expressNumber);
            // 如果无相关物流信息写入新订阅信息
            if (empty($results)) {

                $expressInfo = array();
                //$expressInfo['order_id']      = '';
                $expressInfo['api_status']      = $expressData->status;
                $expressInfo['express_company'] = $expressData->lastResult->com;
                $expressInfo['express_number']  = $expressData->lastResult->nu;
                $expressInfo['ischeck_packer']  = $expressData->lastResult->ischeck;
                $expressInfo['express_state']   = $expressData->lastResult->state;

                // 转码数据
                $exp_arr = array();
                $i=0;
                foreach ($expressData->lastResult->data as $k => $v) {
                    $exp_arr[$i]['time']    = $v->time;
                    $exp_arr[$i]['ftime']   = $v->ftime;
                    $exp_arr[$i]['context'] = $v->context;
                    $i++;
                }

                $expressInfo['express_data'] = serialize($exp_arr);
                $expressInfo['created_at'] = date('Y-m-d H:i:s', time());
                $expressInfo['updated_at'] = date('Y-m-d H:i:s', time());

                $insert = DB::table($this->DBTABLE)->insert($expressInfo);

            } else {
                // 快递信息已存在进行更新
                $expressInfo = array();
                $expressInfo['express_number']  = $expressData->lastResult->nu;
                $expressInfo['api_status']      = $expressData->status;
                $expressInfo['ischeck_packer']  = $expressData->lastResult->ischeck;
                $expressInfo['express_company'] = $expressData->lastResult->com;

                $exp_arr = array();
                $i = 0;
                foreach ($expressData->lastResult->data as $k => $v) {
                    $exp_arr[$i]['time']    = $v->time;
                    $exp_arr[$i]['ftime']   = $v->ftime;
                    $exp_arr[$i]['context'] = $v->context;
                    $i++;
                }

                $expressInfo['express_data'] = serialize($exp_arr);
                $expressInfo['updated_at'] = date('Y-m-d H:i:s', time());

                $update = DB::table($this->DBTABLE)
                ->where(array('express_number' => $expressInfo['express_number']))
                ->update($expressInfo);

                // 对订单状态进行更新
                if ($expressData->lastResult->state == 3) {

                    // $orderId = self::getOrderIdByExpressNumber($expressData->lastResult->nu);

                    // if ($orderId !== false) {
                    //     self::updateOrderStatus($orderId[0]->order_id);
                    // }
                }
            }

            $response = '{"result":"true",  "returnCode":"200","message":"成功"}';
            return $response;
            //要返回成功（格式与订阅时指定的格式一致），不返回成功就代表失败，没有这个30分钟以后会重推
        } catch(Exception $e) {
            $response = '{"result":"false", "returnCode":"500","message":"失败"}';
            return $response;
            //保存失败，返回失败信息，30分钟以后会重推
        }

    }

    /**
     * 通过快递单号从数据库中获取快递信息
     * @param  String $expressNumber 快递单号
     * @return mixed 成功返回true 失败返回false
     *
     */
    public function getExpressInfoByExpressNumber($expressNumber){
        if (empty($expressNumber)) {
            return false;
        }

        try {
            $results = DB::select('select * from ' . $this->DBTABLE . ' where express_number = :express_number', ['express_number' => $expressNumber]);
        } catch (Exception $e) {
            //TODO 写入错误日志
            return false;
        }

        // 处理返回值的问题

        return $results;
    }

    /**
     * 生成salt串
     * @param  string $expressNumber 快递单号
     * @return mix         成功返回salt串，失败返回false
     */
    public function hashSalt($expressNumber){
        $salt = env('SALT');
        return md5($expressNumber . $salt);
    }


    public function realTimeGetExpressData($expressNumber, $expressCompany='', $expressForm='', $expressTo=''){

        if (empty($expressNumber)) {
            return false;
        }


        $post_data             = array();
        $post_data["customer"] = env('CUSTOMER_ID');
        $key                   = env('AUTH_KEY') ;
        $post_data["param"]    = '{"com":"' . $expressCompany . '","num":"' . $expressNumber . '"}';


        $url = env('REAL_TIME_URL');
        $post_data["sign"] = md5($post_data["param"].$key.$post_data["customer"]);
        $post_data["sign"] = strtoupper($post_data["sign"]);

        $o="";

        foreach ($post_data as $k=>$v)
        {
            $o.= "$k=".urlencode($v)."&";       //默认UTF-8编码格式
        }
        $post_data=substr($o,0,-1);



        try {

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_URL,$url);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
            curl_setopt($ch, CURLOPT_TIMEOUT,10);
            $output = curl_exec($ch);

        } catch (Exception $e) {
            return false;
        }

        $data = str_replace("\&quot;",'"',$output);
        $data = json_decode($data,true);


        if (empty($data)) {
            return false;
        }

        if (isset($data['returnCode']) && $data['returnCode'] == '500') {
            return false;
        }


        if ($data['status'] != '200') {
            return false;
        }

        return $data;
    }


    public function updateExpressByResult($expressResult){

        if (empty($expressResult) || $expressResult == false) {
            return false;
        }

        $responseData = array();
        // 将数据存入数据库中
        $expressInfo = array();
        $expressInfo['order_id']    = '';

        if ($expressResult['state'] == '3') {
            $expressInfo['api_status'] = 'shutdown';
            // 签收状态，变更订单状态
            if (!empty($expressResult['nu'])) {
                // 取得订单id
                // $orderId = self::getOrderIdByExpressNumber($expressResult['nu']);

                // if ($orderId != false) {

                //     self::updateOrderStatus($orderId[0]->order_id);
                // }
            }
        } else {
            $expressInfo['api_status'] = $expressResult['status'];

            // 取得订单id
            // $orderId = self::getOrderIdByExpressNumber($expressResult['nu']);

            // if ($orderId != false) {

            //     self::updateOrderStatus($orderId[0]->order_id);
            // }

        }


        $expressInfo['express_company'] = $expressResult['com'];
        $expressInfo['express_number']  = $expressResult['nu'];
        $expressInfo['ischeck_packer']  = $expressResult['ischeck'];
        $expressInfo['express_state']   = $expressResult['state'];
        // // 转码数据
        $exp_arr = array();
        $i=0;
        foreach ($expressResult['data'] as $k => $v) {
            $exp_arr[$i]['time']    = $v['time'];
            $exp_arr[$i]['ftime']   = $v['ftime'];
            $exp_arr[$i]['context'] = $v['context'];
            $i++;
        }
        $expressInfo['express_data'] = serialize($exp_arr);
        $expressInfo['updated_at'] = date('Y-m-d H:i:s', time());

        $update = DB::table($this->DBTABLE)
        ->where(array('express_number' => $expressInfo['express_number']))
        ->update($expressInfo);

        return true;
    }

    /**
     * 更新订单状态
     * @param  [type] $orderId [description]
     * @return [type]          [description]
     */
    public function updateOrderStatus($orderId){
        /**

        $result                 = DB::table('orders')
                                  ->where(array('order_id'=>$orderId,'state'=>4))
                                  ->update(array('state'=>6,'updated_at'=>time()));

        //添加订单操作
        $input = array('order_id'=>$orderId,
                       'user_id'=>1,
                       'order_state'=>4,
                       'over_order_state'=>6,
                       'iden'=>0,
                       'created_at' => time()
                );

        $result       = DB::table('order_operations')->insert($input);
        */
    }

    public function getOrderIdByExpressNumber($expressNumber){
        if (empty($expressNumber)) {
            return false;
        }

        $results = DB::select('select * from ' . 'order_express' . ' where order_express_id = :order_express_id', ['order_express_id' => $expressNumber]);

        if ($results === false) {
            return false;
        }

        return $results;

    }

    function test($input){
        return GeneralTool::createResult('','M00000');
    }
}
